﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.Net.DesignByContract;
using Common.Net.Utilities;
using System.Windows.Forms;

namespace ClearUnit.Exceptions
{
    public static class AssertionExceptionFactory
    {
        static string FormatExpectedActual(string expectedFormatted, object actualFormatted)
        {
            return
                string.Format("Expected: '{0}'", expectedFormatted) + Environment.NewLine +
                string.Format("  Actual: '{0}'", actualFormatted);
        }

        static AssertionException Internal_OtherExpected(object expected, object actual, string format, params object[] args)
        {
            string message = string.Format(format, args) + Environment.NewLine;
            message += FormatExpectedActual(FormatObject(expected), FormatObject(actual));
            return new AssertionException(message);
        }

        static string FormatObject(object obj)
        {
            if (obj == null)
                return "(null)";

            if (obj is Type)
                return ((Type)obj).Name;

            return obj.ToString();
        }

        static string ExplainIfNeeded(string message, string explanationFormat, object[] args)
        {
            string result = message;

            if (!explanationFormat.IsNullOrEmpty())
                result += Environment.NewLine + explanationFormat.Format(args);

            return result;
        }

        public static AssertionException OtherValueExpected<T>(T expected, T actual, string format, params object[] args)
        {
            return Internal_OtherExpected(expected, actual, ExplainIfNeeded("Other value expected", format, args));
        }

        public static AssertionException OtherBoolValueExpected(string format, params object[] args)
        {
            return new AssertionException(string.Format(format, args));
        }

        public static AssertionException OtherTypeExpected(Type expected, Type actual)
        {
            return Internal_OtherExpected(expected, actual, "Other type expected");
        }

        public static AssertionException OtherExceptionExpected<TExpected>(Exception actual)
        {
            return Internal_OtherExpected(typeof(TExpected), actual, "Expected other exception to be thrown");
        }

        public static AssertionException AnyExceptionExpected<TExpected>(object value)
        {
            return Internal_OtherExpected(typeof(TExpected).Name, value, "Expected exception to be thrown, got return value");
        }

        public static AssertionException Assertion(string format, params object[] args)
        {
            return new AssertionException(format.Format(args));
        }
    }
}
